﻿using System;
using System.Security.Cryptography;
using System.Text;

namespace INdTFramework.Commons
{
    public class EncryptionUtils
    {
        static UTF8Encoding ByteConverter = new UTF8Encoding();

        public static string GetHashBySHA256(string data, bool lowercase = false)
        {
            if (data == null)
            {
                throw new ArgumentNullException("data");
            }

            var dataBytes = ByteConverter.GetBytes(data);

            var sha256 = new SHA256Managed();
            var hash = sha256.ComputeHash(dataBytes);
            
            var hexadecimal = GetStringHexadecimal(hash, lowercase);

            return hexadecimal;
        }

        public static byte[] RSAEncrypt(string data, int keySize, string containerName)
        {
            if (data == null)
            {
                throw new ArgumentNullException("The data paramenter can not be null");
            }
            else if (!IsValidKeySize(keySize))
            {
                throw new ArgumentException("The key size must be greater than 448 and power of 2 number");
            }
            else if (containerName == null)
            {
                throw new ArgumentNullException("The containerName can not be null");
            }

            RSADeleteKeyCSP(containerName);
            RSAPersistKeyCSP(keySize, containerName);


            var cspParams = new CspParameters();
            cspParams.KeyContainerName = containerName;
            var RSA = new RSACryptoServiceProvider(cspParams);
            var dataToEncrypt = ByteConverter.GetBytes(data);

            var encryptedData = RSA.Encrypt(dataToEncrypt, true);
            return encryptedData;
        }

        public static string RSADecrypt(byte[] dataToDecrypt, string containerName)
        {
            if (dataToDecrypt == null)
            {
                throw new ArgumentNullException("The dataToEncrypt can not be null");
            }

            var cspParams = new CspParameters();
            cspParams.KeyContainerName = containerName;

            var RSA = new RSACryptoServiceProvider(cspParams);
            var decryptedData = RSA.Decrypt(dataToDecrypt, true);
            var data = ByteConverter.GetString(decryptedData, 0, decryptedData.Length);
            return data;
        }

        static void RSAPersistKeyCSP(int keySize, string containerName)
        {
            var cspParams = new CspParameters();
            cspParams.KeyContainerName = containerName;
            var RSA = new RSACryptoServiceProvider(keySize, cspParams);
        }

        static void RSADeleteKeyCSP(string containerName)
        {
            var cspParams = new CspParameters();
            cspParams.KeyContainerName = containerName;
            
            var RSA = new RSACryptoServiceProvider(cspParams);
            RSA.PersistKeyInCsp = false;

            RSA.Clear();
        }

        static bool IsValidKeySize(int keySize)
        {
            if ((keySize >= 448) && (keySize <= 16384) && (keySize % 8 == 0))
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public static string GetStringHexadecimal(byte[] data, bool lowercase = false)
        {
            if (data == null)
            {
                throw new ArgumentNullException("data");
            }

            var dataFormat = "{0:X2}";

            if (lowercase)
            {
                dataFormat = "{0:x2}";
            }

            var builder = new StringBuilder();

            foreach (byte b in data)
            {
                builder.AppendFormat(dataFormat, b);
            }

            return builder.ToString();
        }
        
    }
}
